﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using EPiBoost.Core.Model.TemplateParameters;
using EPiServer;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.Editor;
using EPiServer.Filters;
using EPiServer.Framework.Localization;
using EPiServer.Framework.Serialization;
using EPiServer.Framework.Web;
using EPiServer.ServiceLocation;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Web;
using EPiServer.Web;
using EPiServer.Web.Mvc;
using EPiServer.Web.Mvc.Html;
using EPiServer.Web.PropertyControls;
using EPiServer.Web.Routing;

namespace EPiBoost.Core.Web.Mvc.Html
{

	public static class ContentAreaExtensions
	{

		public static MvcHtmlString ContentArea(this HtmlHelper html, EPiServer.Core.ContentArea contentArea)
		{
			return html.ContentArea(contentArea, html.ViewContext.HttpContext.GetService<IContentRenderer>(null), html.ViewContext.HttpContext.GetService<TemplateResolver>(null), html.ViewContext.HttpContext.GetService<ObjectSerializerFactory>(null), new FilterContentForVisitor(TemplateTypeCategories.MvcPartialView, (string)(html.ViewContext.ViewData["tag"] as string)));
		}

		public static MvcHtmlString ContentArea(this HtmlHelper html, EPiServer.Core.ContentArea contentArea, IContentRenderer contentRenderer, TemplateResolver templateResolver, ObjectSerializerFactory objectSerializerFactory, IContentFilter contentFilter)
		{
			return HtmlString.GetMvcHtmlString(delegate(System.IO.TextWriter writer)
			{
				html.RenderContentArea(contentArea, contentRenderer, templateResolver, objectSerializerFactory, contentFilter);
			});
		}

		private static bool EditMode(HtmlHelper html)
		{
			return (bool)(html.ViewContext.RequestContext.GetContextMode() == ContextMode.Edit);
		}


		internal static ContextMode GetContextMode(this System.Web.Routing.RequestContext reqContext)
		{
			return Web.Mvc.Html.Helpers.GetContextMode(reqContext.RouteData);
		}

		public static void RenderContentArea(this HtmlHelper html, EPiServer.Core.ContentArea contentArea)
		{
			html.RenderContentArea(contentArea, html.ViewContext.HttpContext.GetService<IContentRenderer>(null), html.ViewContext.HttpContext.GetService<TemplateResolver>(null), html.ViewContext.HttpContext.GetService<ObjectSerializerFactory>(null), new FilterPublished());
		}
		

		public static void RenderContentArea(this HtmlHelper html, EPiServer.Core.ContentArea contentArea, IContentRenderer contentRenderer, TemplateResolver templateResolver, ObjectSerializerFactory objectSerializerFactory, IContentFilter contentFilter)
		{
			

				if ((contentArea != null) && !contentArea.IsEmpty)
				{
					/* Added */
					int i = 0;
					int total = contentArea.Contents.Count();

					var wrapperSettings = Helpers.LoadWrapperSetttings(html);
					var rowSettings = Helpers.LoadRowSetttings(html);
					/* End Added */

					string str = (string) (html.ViewContext.ViewData["customtag"] as string);

					//				/* Added */
					//				if (string.IsNullOrEmpty(str))
					//				{
					//					str = rowSettings.Element;
					//				}
					//				/* End Added */

					if (string.IsNullOrEmpty(str))
					{
						str = "div";
					}

					string str2 = (string) (html.ViewContext.ViewData["cssclass"] as string);

					//				/* Added */
					//				if (string.IsNullOrEmpty(str2))
					//				{
					//					str2 = rowSettings.Class;
					//				}
					//				/* End Added */

					string str3 = (string) (html.ViewContext.ViewData["childrencustomtagname"] as string);

					/* Added */
					if (string.IsNullOrEmpty(str3))
					{
						str3 = wrapperSettings.Element;
					}
					/* End Added */

					if (string.IsNullOrEmpty(str3))
					{
						str3 = "div";
					}
					string str4 = (string) (html.ViewContext.ViewData["childrencssclass"] as string);

					/* Added */
					if (string.IsNullOrEmpty(str4))
					{
						str4 = wrapperSettings.Class;
					}
					/* End Added */


					if (!EditMode(html) /* Added */&& !rowSettings.DisableWrapperElement /* End Added */)
					{
						html.ViewContext.Writer.Write(string.Format(System.Globalization.CultureInfo.InvariantCulture, "<{0}{1}>",
						                                            new object[]
							                                            {
								                                            str,
								                                            string.IsNullOrEmpty(str2)
									                                            ? string.Empty
									                                            : string.Format(System.Globalization.CultureInfo.InvariantCulture,
									                                                            " class=\"{0}\"", new object[] {str2})
							                                            }));
					}
					System.Collections.Generic.IEnumerable<IContent> enumerable = EditMode(html)
						                                                              ? contentArea.Contents
						                                                              : contentArea.FilteredContents;

					foreach (IContent content in enumerable)
					{
						using (new ContentAreaContext(html.ViewContext.RequestContext, content.ContentLink))
						{
							TemplateModel templateModel = templateResolver.Resolve(html.ViewContext.HttpContext, content.GetOriginalType(),
							                                                       content, TemplateTypeCategories.MvcPartial,
							                                                       (string) (html.ViewContext.ViewData["tag"] as string));
							if (EditMode(html))
							{
								/* Added */
								Helpers.TryOpenRow(html, rowSettings, i, total);

								var newStr4 = str4 +
								              (wrapperSettings.EnableInEditMode
									               ? " " + Helpers.GetWrapperClassNames(wrapperSettings, total, rowSettings, i)
									               : null);
								/* End Added */

								html.ViewContext.Writer.Write(string.Format(System.Globalization.CultureInfo.InvariantCulture,
								                                            "<{0} {1}=\"{2}\" {3}=\"{4}\"{5}{6}>",
								                                            new object[]
									                                            {
										                                            str3, "data-epi-block-id", content.ContentLink.ToString(),
										                                            "data-epi-content-name", content.Name,
										                                            string.IsNullOrEmpty(str4)
											                                            ? string.Empty
											                                            : string.Format(
												                                            System.Globalization.CultureInfo.InvariantCulture,
												                                            " class=\"{0}\"", new object[] {newStr4}),
										                                            RenderInfoAttribute(templateModel, objectSerializerFactory)
									                                            }));

								try
								{
									html.RenderContentData(content, true, templateModel, contentRenderer);
								}
								catch(Exception ex)
								{
									WriteException(html, ex);
								}

								html.ViewContext.Writer.Write(string.Format(System.Globalization.CultureInfo.InvariantCulture, "</{0}>",
								                                            new object[] {str3})); /* Added */

								Helpers.TryCloseRow(html, rowSettings, i, total);
								/* End Added */
							}
							else if (!contentFilter.ShouldFilter(content))
							{
								/* Added */
								Helpers.TryOpenRow(html, rowSettings, i, total);
								bool wrapperOpen = Helpers.OpenWrapper(html, wrapperSettings, i, total, rowSettings);
								/* End Added */

								if (!wrapperSettings.DisableWrapperElement) //added
									html.ViewContext.Writer.Write(string.Format(System.Globalization.CultureInfo.InvariantCulture, "<{0}{1}>",
									                                            new object[]
										                                            {
											                                            str3,
											                                            string.IsNullOrEmpty(str4)
												                                            ? string.Empty
												                                            : string.Format(
													                                            System.Globalization.CultureInfo.InvariantCulture,
													                                            " class=\"{0}\"", new object[] {str4})
										                                            }));
								try{
									html.RenderContentData(content, true, templateModel, contentRenderer);
								}
								catch (Exception ex)
								{
									WriteException(html, ex);
								}

								if (!wrapperSettings.DisableWrapperElement) // added
									html.ViewContext.Writer.Write(string.Format(System.Globalization.CultureInfo.InvariantCulture, "</{0}>",
									                                            new object[] {str3}));

								/* Added */
								if (wrapperOpen)
								{
									Helpers.CloseWrapper(html, wrapperSettings);
								}
								Helpers.TryCloseRow(html, rowSettings, i, total);
								/* End Added */
							}
						}

						i++; // added
					}
					
					if (!EditMode(html) /* Added */ && !rowSettings.DisableWrapperElement /* End Added */  )
					{
						html.ViewContext.Writer.Write(string.Format(System.Globalization.CultureInfo.InvariantCulture, "</{0}>", new object[] { str }));
					}
				}
		
		}

		private static void WriteException(HtmlHelper html, Exception ex)
		{
			if (Configuration.CustomDisplayTemplates.ContentAreaCatchErrorsEnabled)
			{
				if (EditMode(html))
				{
					var ex1 = ex.InnerException ?? ex;
					html.ViewContext.Writer.Write(string.Format("<div class=\"epiboost-block-error\"><h2>ERROR:</h2><p class=\"epiboost-error-message\">{0}</p><p class=\"epiboost-error-stack\">{1}</p></div>", ex1.Message, ex1.StackTrace.Replace("\n", "<br/>\n")));
				}
			}
			else
			{
				throw ex;
			}
		}

		private static string RenderInfoAttribute(TemplateModel templateModel, ObjectSerializerFactory objectSerializerFactory)
		{
			if (templateModel != null)
			{
				return string.Empty;
			}
			System.Collections.Generic.Dictionary<string, object> dictionary = new System.Collections.Generic.Dictionary<string, object>();
			dictionary.Add("missingrenderer", "true");
			IObjectSerializer serializer = objectSerializerFactory.GetSerializer("application/json");
			System.Text.StringBuilder builder = new System.Text.StringBuilder();
			serializer.Serialize(new System.IO.StringWriter(builder), dictionary);
			return string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}='{1}'", new object[] { "data-epi-block-info", builder.ToString() });
		}
	}
}


